package com.rds.common.utils.rds;

import com.rds.common.core.domain.AjaxResult;
import com.rds.common.core.domain.entity.DynamicVo;
import com.rds.common.core.service.IDynamicService;
import com.rds.common.utils.DateUtils;
import com.rds.common.utils.SecurityUtils;
import com.rds.common.utils.StringUtils;
import com.rds.common.utils.uuid.SnowFlakeUtils;
import org.apache.commons.lang3.math.NumberUtils;

import java.util.*;

/**
 * 对象版本修订功能类
 * @version : 1.0
 * @Copyright: Copyright(c) 2020-2021 All right reserved
 * @Company: GUANGZHOU RDS Co.,LTD
 * @author: LiChuanlong
 * @create Date : 2021/12/18 : 23:00
 */
public class ObjectReviseUtil {
    private final IDynamicService dynamicService;


    public ObjectReviseUtil(IDynamicService dynamicService){
        this.dynamicService = dynamicService;
    }

    /**
     * 修订对象
     * @param id 当前被修订对象Id
     * @param reviseCategory 修订对象类型(document,part,...)
     * @param floatFile 是否带文件修订(true 是;false 否)
     * @return 修订成功/失败信息(Map)
     */
    public AjaxResult reviseObject(Long id,String reviseCategory,boolean floatFile){
        AjaxResult ajaxResult = new AjaxResult();
        int rows = 0;
        String originalRevision = "A";//默认原始版本是A
        Integer originalPolicyId = 0; //原始策略Id默认为 0
        long originalStateId = 0L ; //原状态Id 默认为0
        if("document".equalsIgnoreCase(reviseCategory)){
            /* 这里一个对象Id 只能查询出一个对象 **/
            List<Map<String,Object>> list = listDocumentVersion(dynamicService,id);
            Map<String,Object> originalDocument = list.get(list.size()-1);//如果有多个版本 取最后一个版本数据
            originalRevision = (String) originalDocument.get("revision");
            /*准备设置状态 修改版本的状态 必须是当前策略的第一个状态**/
            originalPolicyId = (Integer) originalDocument.get("policyid");
            originalStateId =  Long.parseLong(String.valueOf(originalDocument.get("stateid")));

            Map<Boolean,String> revisedMap = checkRevised(originalStateId, Long.valueOf(originalPolicyId));
            if(revisedMap.containsKey(true)){
                int newStateId = Integer.parseInt(revisedMap.get(true));
                String newRevision = getNextRevision(originalRevision);
                String username = SecurityUtils.getUsername();
                //复制原Document
                Map<String,Object> reviseDocument=originalDocument;
                reviseDocument.put("stateid",newStateId);
                reviseDocument.put("revision",newRevision);
                reviseDocument.put("id",SnowFlakeUtils.nextId());
                rows = dynamicService.insertData("rda_document",reviseDocument);//生成新的文档对象

                /*开始处理原始文档中的附件**/
                if(floatFile){ //为true 表示带文件修订
                    DynamicVo fileDynamicVo=new DynamicVo();
                    ArrayList<String> fileQueryWrapper=new ArrayList<>();
                    fileQueryWrapper.add("and doc_id="+id);
                    fileQueryWrapper.add("and status=1");
                    fileDynamicVo.setQueryWrapper(fileQueryWrapper);
                    List<HashMap<String,Object>> files=dynamicService.selectList(fileDynamicVo);
                    if(files.size() > 0 ){
                        List<Map<String, Object>> fileBatchList=new ArrayList<>();
                        for(Iterator<HashMap<String,Object>> fileIt = files.iterator(); fileIt.hasNext();){
                            HashMap<String,Object> f =  fileIt.next();
                            HashMap<String,Object> f2 = new HashMap<>();
                            Long fid=SnowFlakeUtils.nextId();
                            f2.put("id",fid);
                            f2.put("path",f.get("path"));
                            f2.put("doc_id",reviseDocument.get("id"));
                            f2.put("file_id",fid);
                            f2.put("name",f.get("fileName"));
                            f2.put("file_size",f.get("fileSize"));
                            f2.put("username",username);
                            f2.put("create_time", DateUtils.getNowDate());
                            fileBatchList.add(f2);
                        }
                        dynamicService.insertBatchData("rda_file",fileBatchList);
                    }
                }
                /*修订后设置更改标记属性值 2021-12-19**/
                String policyName = (String) dynamicService.selectDataById("rda_policy", (Long) reviseDocument.get("policyid")).get("Name");
                /*版本不能是A-Z 并且策略不能是智领策略开头的才会设置更改标记**/
                if(!newRevision.matches("^[A-Z]$") && !policyName.startsWith("zl")){
                    String mark = transformChangeMark(Integer.parseInt(newRevision));
                    ArrayList<String> updateWrapper=new ArrayList<>();
                    updateWrapper.add("id="+reviseDocument.get("id"));
                    reviseDocument.put("ChangeMark",mark);
                    dynamicService.updateData("rda_document",reviseDocument,updateWrapper);
                }
                /*修订文档时记录历史记录 2021-12-13*/
                StringBuilder details = new StringBuilder();
                details.append("由").append(originalDocument.get("name")).append("修订").append(";");
                details.append("修订版本:").append(originalRevision).append("-->").append(newRevision);
                new HistoryRecordUtil(dynamicService).reviseHistory((Long) reviseDocument.get("id"), "修订",(Integer) reviseDocument.get("stateid"),"文档管理",details);

                ajaxResult = new AjaxResult(rows > 0 ? 0 : -1,
                                            rows > 0 ? "修订成功!" : "修订失败!",
                                            rows > 0 ? reviseDocument : "");
                //return rows > 0 ? AjaxResult.success("修订成功!") : AjaxResult.error("修订失败!");
            }else {
                //return AjaxResult.error(revisedMap.getOrDefault(false, "出现未知错误,请联系管理员!"));
                ajaxResult = new AjaxResult(-1,revisedMap.getOrDefault(false, "出现未知错误,请联系管理员!"),"");
            }
        }else{
            //return AjaxResult.error( "无相关对象修订程序,请联系管理员!");
            ajaxResult = new AjaxResult(-1,"无相关对象修订程序,请联系管理员!","");
        }
        return ajaxResult;
    }

    /**
     * 根据原始版本获取下一版本
     * @param originalRevision 原始版本
     * @return 根据规则返回下一版本
     */
    private String getNextRevision(String originalRevision){
        String reviseRevision = "1"; //升版后版本 默认版本为 1
        if(NumberUtils.isDigits(originalRevision)){ //如果当前版本是数字
            reviseRevision = String.valueOf(Integer.parseInt(originalRevision) + 1);
        }else if(!NumberUtils.isDigits(originalRevision)){
            if(originalRevision.length() > 1){ //如果是A1,B1,A01,B01,...之类的数据
                String fixPart = originalRevision.substring(0, 1);
                int digit = originalRevision.substring(1).length(); //字母后还剩多少位
                String variPart = StringUtils.isNotBlank(originalRevision.substring(1)) ? originalRevision.substring(1) : "0";
                int newVarPart = Integer.parseInt(variPart)+1;
                reviseRevision = fixPart+String.format("%0"+digit+"d",newVarPart);
            }else{
                int newValue = originalRevision.toUpperCase().getBytes()[0]+1;
                reviseRevision = String.valueOf((char)newValue);
            }
        }
        return reviseRevision;
    }

    /**
     * 检查当前对象是否可被修订
     * @param originalStateId 被修订对象状态Id
     * @param originalPolicyId 被修订对象策略Id
     * @return 能修订返回Map(true,状态Id);不能修订 返回Map(false,错误信息)
     */
    private Map<Boolean,String> checkRevised(Long originalStateId,Long originalPolicyId){
        Map<Boolean,String> returnMap = new HashMap<>();

        DynamicVo dynamicVo=new DynamicVo();
        ArrayList<String> queryWrapper=new ArrayList<>();
        queryWrapper.add("and policyid="+originalPolicyId);
        dynamicVo.setQueryWrapper(queryWrapper);
        dynamicVo.setTableName("rda_state");
        List<HashMap<String,Object>> stateList=dynamicService.selectList(dynamicVo);
        if(stateList.size() > 0 ){
            /*因为查询的时候已经按id 进行正序排列 所有第一个肯定是当前策略的第一个状态***/
            int newState = (Integer) stateList.get(0).get("id");
            int newStateId = Integer.parseInt(String.valueOf(newState)); //当前策略第一个状态的Id
            /*如果当前修订的对象状态不是策略的最后第二个状态(最后一个一般为废弃)  提示 且不让其修订***/
            if(!originalStateId.equals(stateList.get(stateList.size()-2).get("id"))){
                returnMap.put(false,"存在未发布状态对象,不允许修订...");
            }else{
                returnMap.put(true,String.valueOf(newStateId));
            }
        }else{
            returnMap.put(false,"策略["+originalPolicyId+"]查询当前状态列表失败,请联系管理员!");
        }

        return returnMap;
    }

    /**
     * 根据升级后的版本生成对应的更改标记值(仅限文档变更)
     * @param revision 升版后版本
     * @return 更改标记值(1对应a;2对应b;依次类推...)
     */
    private String transformChangeMark(int revision){
        String mark = "";
        if(revision <= 26){
            char sl = (char) (revision-1 + (int) 'a');
            mark = "" + sl;
        }else if(revision > 26 && revision<= 52){
            revision = revision-26;
            char sl = (char) (revision-1 + (int) 'a');
            mark = "" + sl;
            mark=mark+mark;
        }else{
            revision = revision-52;
            char sl = (char) (revision-1 + (int) 'a');
            mark = "" + sl;
            mark=mark+mark+mark;
        }
        return mark;
    }


    /**
     * 获取当前对象所有版本信息
     * @param dynamicService 注解
     * @param id 当前对象Id
     * @return 所有当前对象版本信息(排好序)
     */
    public List<Map<String, Object>> listDocumentVersion(IDynamicService dynamicService,Long id) {
        List<Map<String, Object>> versionList = new LinkedList<>();
        /*查询逻辑:
         *1.如果当前对象是初版(初版对象上recordid 为空),则需要根据当前对象id 作为recordid 查询升版本后的对象;
         *2.如果当前版本非初版,则需要recordid 作为recordid  递归循环查询其他版本(如 A修订B,B修订C,C修订D,...)
         ***/
        //去重临时集合
        List<Long> tempDocIdList = new LinkedList<>();
        /*一个id 只能对应一个唯一值**/
        Map<String, Object> document = dynamicService.selectDataById("rda_document",id);
        Long recordId = (Long) document.get("recordid");
        versionList.add(document);
        tempDocIdList.add(id);
        //如果recordId 为空,那么就说名当前对象是初版;然后查询由这个版本修订的对象
        if("null".equals(String.valueOf(recordId)) || String.valueOf(recordId) == null || "".equals(String.valueOf(recordId))){
            DynamicVo dynamicVo=new DynamicVo();
            ArrayList<String> queryWrapper=new ArrayList<>();
            dynamicVo.setTableName("rda_document");
            queryWrapper.add("and recordid="+id);
            dynamicVo.setQueryWrapper(queryWrapper);
            List<HashMap<String,Object>> documents=dynamicService.selectList(dynamicVo);
            for(HashMap<String,Object> doc : documents){
                recurseSearchDocument(dynamicService,(Long) doc.get("id"),(Long) doc.get("recordid"),versionList,tempDocIdList);
            }
        }else {
            recurseSearchDocument(dynamicService,id,recordId,versionList,tempDocIdList);
        }
        //针对返回结果进行A~Z 排序
        Collections.sort(versionList, new Comparator<Map<String, Object>>() {
            @Override
            public int compare(Map<String, Object> o1, Map<String, Object> o2) {
                return String.valueOf(o1.get("revision")).toUpperCase().getBytes()[0] - String.valueOf(o2.get("revision")).toUpperCase().getBytes()[0];
            }
        });
        return versionList;
    }


    /**
     * 递归获取当前对象所有的版本(无跨层查找)
     * @param dynamicService 注解
     * @param id 当前对象Id
     * @param recordId 当前对象修订前对象Id
     * @param versionList 集合,用户放回数据
     * @param tempDocIdList 集合,用户临时去重
     */
    private static void recurseSearchDocument(IDynamicService dynamicService,Long id,Long recordId,List<Map<String, Object>> versionList,List<Long> tempDocIdList){
        if(!"null".equals(String.valueOf(recordId)) && String.valueOf(recordId) != null && !"".equals(String.valueOf(recordId))){
            //首先查询非初始版本的首版本
            Map<String, Object> document = dynamicService.selectDataById("rda_document",id);
            if(document !=null){
                if(!tempDocIdList.contains((Long) document.get("id")) && StringUtils.isNotBlank(String.valueOf(document.get("id")))){
                    versionList.add(document);
                    tempDocIdList.add((Long) document.get("id"));
                }
            }
            //查出当前当前版本修订出来的其他版本
            DynamicVo dynamicVo=new DynamicVo();
            ArrayList<String> queryWrapper=new ArrayList<>();
            dynamicVo.setTableName("rda_document");
            queryWrapper.add("and recordid="+id);
            dynamicVo.setQueryWrapper(queryWrapper);
            dynamicVo.setOrderBy("order by revision");
            List<HashMap<String,Object>> documents=dynamicService.selectList(dynamicVo);
            for(HashMap<String,Object> doc : documents){
                if(!tempDocIdList.contains((Long) doc.get("id"))){
                    /*去重**/
                    versionList.add(doc);
                    tempDocIdList.add((Long) doc.get("id"));
                }
            }
            //在查询当前对象作为修订版本的原始对象,以当前对象Id作为recordId查询修订版本对象(如D由C修订而来 那么当前版本是C时 就可以查询出D)
            DynamicVo dynamicVo2=new DynamicVo();
            ArrayList<String> queryWrapper2=new ArrayList<>();
            dynamicVo2.setTableName("rda_document");
            queryWrapper2.add("and recordid="+id);
            dynamicVo2.setQueryWrapper(queryWrapper);
            dynamicVo2.setOrderBy("order by revision");
            List<HashMap<String,Object>> documents2=dynamicService.selectList(dynamicVo2);
            if(documents2.size() > 0 ){
                for(HashMap<String,Object> doc : documents2){
                    if(!tempDocIdList.contains((Long) doc.get("id"))){
                        //去重
                        versionList.add(doc);
                        tempDocIdList.add((Long) doc.get("id"));
                    }
                }
            }
            //有可能当前版本不是由最初的版本升级而来,是由非初始版本修订,那么还得需要recordId 去查询(所以这里再次调用此方法,一直查询到recordId 为空[表示为首版对象])
            if(document !=null)recurseSearchDocument(dynamicService,id, (Long) document.get("recordid"),versionList,tempDocIdList);

            /*跨层查询处理 begin **/
            //如果当前查询版本和最高版本没有任何关系(如 当前版本为B,C由B版本修订;D由C版本修订;需要查询到D版本数据)
            //首先要通过B找到C(C 又是由A版升级而来) 然后在通过C找到D,依次类推...
            SearchNoContiDocument(dynamicService,id,versionList,tempDocIdList);
            /*跨层查询处理 end**/
        }
    }

    /**
     * 获取当前对象所有的版本(有跨层查找)
     * @param dynamicService 注解
     * @param id 当前对象Id
     * @param versionList 集合,用户放回数据
     * @param tempDocIdList 集合,用户临时去重
     */
    private static void SearchNoContiDocument(IDynamicService dynamicService,Long id,List<Map<String, Object>> versionList,List<Long> tempDocIdList){
        //System.out.println("--->>>id:"+id);
        Map<String, Object> document = dynamicService.selectDataById("rda_document",id);
        if(!tempDocIdList.contains((Long) document.get("id"))){
            versionList.add(document);
            tempDocIdList.add((Long) document.get("id"));
        }
        //System.out.println("--->>>tempDocIdList:"+tempDocIdList);
        //System.out.println("--->>>tempDocIdList size:"+tempDocIdList.size());

        for(int index = 0; index < tempDocIdList.size();index++){
            Long docId = tempDocIdList.get(index);
            //System.out.println("docId = " + docId);
            DynamicVo dynamicVo=new DynamicVo();
            ArrayList<String> queryWrapper=new ArrayList<>();
            dynamicVo.setTableName("rda_document");
            queryWrapper.add("and recordid="+docId);
            dynamicVo.setQueryWrapper(queryWrapper);
            dynamicVo.setOrderBy("order by revision");
            List<HashMap<String,Object>> documents=dynamicService.selectList(dynamicVo);
            //System.out.println("documents size= " + documents.size());
            for(HashMap<String,Object> document2 : documents){
                if(!tempDocIdList.contains((Long) document2.get("id")) && StringUtils.isNotBlank(String.valueOf(document2.get("id")))){
                    versionList.add(document2);
                    tempDocIdList.add((Long) document2.get("id"));
                }
            }
        }
    }


}
